/***************************************************************
 * Name:      wxTsina_GUIMain.cpp
 * Purpose:   Code for Application Frame
 * Author:    Gui Qing (guiqing0402@163.com)
 * Created:   2010-11-13
 * Copyright: Gui Qing (http://t.sina.com.cn/guiqing0402)
 * License:
 **************************************************************/
#include <vector>
#include <map>
#include <stdexcept>
#include <wx/msgdlg.h>
#include <wx/utils.h>
#include <wx/mstream.h>
#include "wxTsina_GUIMain.h"
#include "GlobalConfig.h"
#include "Utils.h"
#include "CFollowersQueryInc.h"
#include "Backend.h"
#include "CLogin.h"

#ifdef UNIT_TEST
    #include "UnitTest.h"
#endif


//(*InternalHeaders(wxTsina_GUIFrame)
#include <wx/artprov.h>
#include <wx/bitmap.h>
#include <wx/intl.h>
#include <wx/image.h>
#include <wx/string.h>
//*)

/***************************************************************
*I think I need some UML design to clearify these compilcated status changing
*Sometimes , I couldn't figure out some var is changed somewhere or not
*Such as unfollowed_xxx.size() == 0 ?
***************************************************************/


//helper functions
enum wxbuildinfoformat {
    short_f, long_f };

wxString wxbuildinfo(wxbuildinfoformat format)
{
    wxString wxbuild(wxVERSION_STRING);

    if (format == long_f )
    {
#if defined(__WXMSW__)
        wxbuild << _T("-Windows");
#elif defined(__UNIX__)
        wxbuild << _T("-Linux");
#endif

#if wxUSE_UNICODE
        wxbuild << _T("-Unicode build");
#else
        wxbuild << _T("-ANSI build");
#endif // wxUSE_UNICODE
    }

    return wxbuild;
}

const int WINDOW_WIDTH = 505;
const int WINDOW_HEIGHT = 382;
const int FUNCTION_BTN_WIDTH = 102;
const int FUNCTION_BTN_HEIGHT = 28;
const int LOGIN_BTN_WIDTH = 86;
const int LOGIN_BTN_HEIGHT = 28;
const int LOGIN_VERIFIER_BTN_WIDTH = 186;
const int LOGIN_VERIFIER_BTN_HEIGHT = 26;

//(*IdInit(wxTsina_GUIFrame)
const long wxTsina_GUIFrame::ID_STATICTEXT1 = wxNewId();
const long wxTsina_GUIFrame::ID_TEXTCTRL1 = wxNewId();
//const long wxTsina_GUIFrame::ID_STATICTEXT2 = wxNewId();
const long wxTsina_GUIFrame::ID_TEXTCTRL2 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON_GET_VERIFIER = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON1 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON2 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON3 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON4 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON5 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON6 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON7 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON8 = wxNewId();
const long wxTsina_GUIFrame::ID_STATICTEXT3 = wxNewId();
const long wxTsina_GUIFrame::ID_GAUGE1 = wxNewId();
const long wxTsina_GUIFrame::ID_STATICTEXT4 = wxNewId();
const long wxTsina_GUIFrame::ID_STATICTEXT5 = wxNewId();
const long wxTsina_GUIFrame::ID_GAUGE2 = wxNewId();
const long wxTsina_GUIFrame::ID_STATICTEXT6 = wxNewId();
const long wxTsina_GUIFrame::ID_PANEL1 = wxNewId();
const long wxTsina_GUIFrame::ID_RADIOBUTTON1 = wxNewId();
const long wxTsina_GUIFrame::ID_RADIOBUTTON2 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON9 = wxNewId();
const long wxTsina_GUIFrame::ID_BITMAPBUTTON1 = wxNewId();
const long wxTsina_GUIFrame::ID_STATICTEXT7 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON10 = wxNewId();
const long wxTsina_GUIFrame::ID_BUTTON11 = wxNewId();
const long wxTsina_GUIFrame::ID_TEXTCTRL3 = wxNewId();
//const long wxTsina_GUIFrame::ID_PANEL3 = wxNewId();
const long wxTsina_GUIFrame::ID_NOTEBOOK2 = wxNewId();
const long wxTsina_GUIFrame::ID_PANEL2 = wxNewId();
const long wxTsina_GUIFrame::ID_NOTEBOOK1 = wxNewId();
const long wxTsina_GUIFrame::idMenuQuit = wxNewId();
const long wxTsina_GUIFrame::idMenuAbout = wxNewId();
const long wxTsina_GUIFrame::ID_STATUSBAR1 = wxNewId();
//*)

const long wxTsina_GUIFrame::ID_AT_ME = wxNewId();

wxDEFINE_EVENT(EVT_UPDATE_SUB_GAUGE, wxThreadEvent);
wxDEFINE_EVENT(EVT_PULSE_SUB_GAUGE, wxThreadEvent);
wxDEFINE_EVENT(EVT_UPDATE_TOTAL_GAUGE, wxThreadEvent);
wxDEFINE_EVENT(EVT_PULSE_TOTAL_GAUGE, wxThreadEvent);
wxDEFINE_EVENT(EVT_GET_PIN_DONE, wxThreadEvent);
wxDEFINE_EVENT(EVT_LOGIN_DONE, wxThreadEvent);
wxDEFINE_EVENT(EVT_CF_SYNC_DONE, wxThreadEvent);

BEGIN_EVENT_TABLE(wxTsina_GUIFrame,wxFrame)
    //(*EventTable(wxTsina_GUIFrame)
    //*)
END_EVENT_TABLE()

wxTsina_GUIFrame::wxTsina_GUIFrame(wxWindow* parent,wxWindowID id):imgList(18,18)
{
    /***When you edit the resource.rc , you shold add the statement in the Main Frame***/
    SetIcon(wxICON(aaaa));
    /*********************************************************************/
    //(*Initialize(wxTsina_GUIFrame)
    wxStaticBoxSizer* StaticBoxSizer2;
    wxFlexGridSizer* FlexGridSizer4;
    wxFlexGridSizer* FlexGridSizer_BtnVerifier;
    wxMenuItem* MenuItem2;
    wxFlexGridSizer* FlexGridSizer3;
    wxMenuItem* MenuItem1;
    wxFlexGridSizer* FlexGridSizer5;
    wxFlexGridSizer* FlexGridSizer9;
    wxFlexGridSizer* FlexGridSizer2;
    wxBoxSizer* BoxSizer2;
    wxMenu* Menu1;
    wxFlexGridSizer* FlexGridSizer7;
    wxStaticBoxSizer* StaticBoxSizer3;
    wxFlexGridSizer* FlexGridSizer8;
    wxFlexGridSizer* FlexGridSizer14;
    wxBoxSizer* BoxSizer1;
    wxFlexGridSizer* FlexGridSizer13;
    wxFlexGridSizer* FlexGridSizer12;
    wxMenuBar* MenuBar1;
    wxFlexGridSizer* FlexGridSizer6;
    wxStaticBoxSizer* StaticBoxSizer1;
    wxFlexGridSizer* FlexGridSizer1;
    wxFlexGridSizer* FlexGridSizer10;
    wxFlexGridSizer* FlexGridSizer11;
    wxMenu* Menu2;


    Create(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("wxID_ANY"));
    SetClientSize(wxSize(WINDOW_WIDTH,WINDOW_HEIGHT));
    Notebook1 = new wxNotebook(this, ID_NOTEBOOK1, wxPoint(168,192), wxSize(496,360), 0, _T("ID_NOTEBOOK1"));
    Panel1 = new wxPanel(Notebook1, ID_PANEL1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T("ID_PANEL1"));
    Panel2 = new wxPanel(Notebook1, ID_PANEL2, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T("ID_PANEL2"));
    FlexGridSizer1 = new wxFlexGridSizer(0, 1, 0, 0);
    FlexGridSizer2 = new wxFlexGridSizer(1, 3, 0, 0);
    /*******Custom Static Box for StaticBoxSizer******/

    sbox1 = new wxStaticBox(Panel1,wxID_ANY, _T("登录"));
    sbox2 = new wxStaticBox(Panel1,wxID_ANY, _T("数据"));
    //the parent* must have been defined until here
    sbox3 = new wxStaticBox(Panel2,wxID_ANY, _T("选择"));

    /******************************************/
    //StaticBoxSizer1 = new wxStaticBoxSizer(wxHORIZONTAL, Panel1, _T("登录"));
    StaticBoxSizer1 = new wxStaticBoxSizer(sbox1, wxHORIZONTAL);

    FlexGridSizer3 = new wxFlexGridSizer(0, 1, 1, 1);

    FlexGridSizer4 = new wxFlexGridSizer(0, 2, 1, 1);
    StaticText1 = new wxStaticText(Panel1, ID_STATICTEXT1, _T(" 授权码 "), wxDefaultPosition, wxSize(47,22), 0, _T("ID_STATICTEXT1"));
    FlexGridSizer4->Add(StaticText1, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 3);
    TextCtrl_verifier = new wxTextCtrl(Panel1, ID_TEXTCTRL1, wxEmptyString, wxDefaultPosition, wxSize(126,22), 0, wxDefaultValidator, _T("ID_TEXTCTRL1"));
    FlexGridSizer4->Add(TextCtrl_verifier, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 3);
    FlexGridSizer3->Add(FlexGridSizer4, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 3);

    //StaticText2 = new wxStaticText(Panel1, ID_STATICTEXT2, _T("密码"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT2"));
    //FlexGridSizer4->Add(StaticText2, 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
    //TextCtrl_password = new wxTextCtrl(Panel1, ID_TEXTCTRL2, wxEmptyString, wxDefaultPosition, wxSize(128,22), wxTE_PASSWORD, wxDefaultValidator, _T("ID_TEXTCTRL2"));
    //FlexGridSizer4->Add(TextCtrl_password, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);


    FlexGridSizer5 = new wxFlexGridSizer(0, 2, 1, 1);
    Button_login_OK = new wxButton(Panel1, ID_BUTTON1, _T("确定"), wxDefaultPosition, wxSize(LOGIN_BTN_WIDTH,LOGIN_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON1"));
    FlexGridSizer5->Add(Button_login_OK, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Button_login_reset = new wxButton(Panel1, ID_BUTTON2, _T("退出登录"), wxDefaultPosition, wxSize(LOGIN_BTN_WIDTH,LOGIN_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON2"));
    FlexGridSizer5->Add(Button_login_reset, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer3->Add(FlexGridSizer5, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 3);


    FlexGridSizer_BtnVerifier = new wxFlexGridSizer(0, 1, 1, 1);
    Button_getVerifier = new wxButton(Panel1, ID_BUTTON_GET_VERIFIER, _T("获取授权码"), wxDefaultPosition, wxSize(LOGIN_VERIFIER_BTN_WIDTH,LOGIN_VERIFIER_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON_GET_VERIFIER"));
    FlexGridSizer_BtnVerifier->Add(Button_getVerifier, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer3->Add(FlexGridSizer_BtnVerifier, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 3);


    StaticBoxSizer1->Add(FlexGridSizer3, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer2->Add(StaticBoxSizer1, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    //StaticBoxSizer2 = new wxStaticBoxSizer(wxHORIZONTAL, Panel1, _T("数据"));
    StaticBoxSizer2 = new wxStaticBoxSizer(sbox2, wxHORIZONTAL);
    FlexGridSizer6 = new wxFlexGridSizer(0, 2, 0, 0);
    Button_start_sync = new wxButton(Panel1, ID_BUTTON3, _T("开始"), wxDefaultPosition, wxSize(FUNCTION_BTN_WIDTH,FUNCTION_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON3"));
    FlexGridSizer6->Add(Button_start_sync, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Button4 = new wxButton(Panel1, ID_BUTTON4, _("Coming Soon"), wxDefaultPosition, wxSize(FUNCTION_BTN_WIDTH,FUNCTION_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON4"));
    Button4->Disable();
    FlexGridSizer6->Add(Button4, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Button_clear_record = new wxButton(Panel1, ID_BUTTON5, _T("清空存储"), wxDefaultPosition, wxSize(FUNCTION_BTN_WIDTH,FUNCTION_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON5"));
    FlexGridSizer6->Add(Button_clear_record, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    ComingSoon = new wxButton(Panel1, ID_BUTTON6, _("Coming Soon"), wxDefaultPosition, wxSize(FUNCTION_BTN_WIDTH,FUNCTION_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON6"));
    ComingSoon->Disable();
    FlexGridSizer6->Add(ComingSoon, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Button_clear_recycler = new wxButton(Panel1, ID_BUTTON7, _T("清空回收站"), wxDefaultPosition, wxSize(FUNCTION_BTN_WIDTH,FUNCTION_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON7"));
    FlexGridSizer6->Add(Button_clear_recycler, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Button8 = new wxButton(Panel1, ID_BUTTON8, _("Coming Soon"), wxDefaultPosition, wxSize(FUNCTION_BTN_WIDTH,FUNCTION_BTN_HEIGHT), 0, wxDefaultValidator, _T("ID_BUTTON8"));
    Button8->Disable();
    FlexGridSizer6->Add(Button8, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer6->Add(8,8,1, wxLEFT|wxALIGN_LEFT|wxALIGN_TOP, 5);
    StaticBoxSizer2->Add(FlexGridSizer6, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer2->Add(StaticBoxSizer2, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer1->Add(FlexGridSizer2, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer7 = new wxFlexGridSizer(0, 1, 0, 0);
    FlexGridSizer8 = new wxFlexGridSizer(0, 2, 0, 0);
    FlexGridSizer9 = new wxFlexGridSizer(0, 1, 0, 0);
    Sub_progress_text = new wxStaticText(Panel1, ID_STATICTEXT3, _T(""), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT3"));
    FlexGridSizer9->Add(Sub_progress_text, 1, wxALL|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
    Gauge_sub = new wxGauge(Panel1, ID_GAUGE1, 100, wxDefaultPosition, wxSize(439,10), 0, wxDefaultValidator, _T("ID_GAUGE1"));
    FlexGridSizer9->Add(Gauge_sub, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer8->Add(FlexGridSizer9, 1, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_LEFT|wxALIGN_TOP, 5);
    BoxSizer1 = new wxBoxSizer(wxHORIZONTAL);
    Sub_progress_percent = new wxStaticText(Panel1, ID_STATICTEXT4, _("0%"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT4"));
    BoxSizer1->Add(Sub_progress_percent, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer8->Add(BoxSizer1, 1, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_LEFT|wxALIGN_BOTTOM, 5);
    FlexGridSizer7->Add(FlexGridSizer8, 1, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_LEFT|wxALIGN_TOP, 3);
    FlexGridSizer11 = new wxFlexGridSizer(0, 2, 0, 0);
    FlexGridSizer12 = new wxFlexGridSizer(0, 1, 0, 0);
    Total_progress_text = new wxStaticText(Panel1, ID_STATICTEXT5, _T("             所有进度"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT5"));
    FlexGridSizer12->Add(Total_progress_text, 1, wxALL|wxALIGN_TOP|wxALIGN_CENTER_HORIZONTAL, 5);
    Gauge_total = new wxGauge(Panel1, ID_GAUGE2, 100, wxDefaultPosition, wxSize(439,10), 0, wxDefaultValidator, _T("ID_GAUGE2"));
    FlexGridSizer12->Add(Gauge_total, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer11->Add(FlexGridSizer12, 1, wxTOP|wxBOTTOM|wxLEFT|wxALIGN_LEFT|wxALIGN_TOP, 5);
    BoxSizer2 = new wxBoxSizer(wxHORIZONTAL);
    Total_progress_percent = new wxStaticText(Panel1, ID_STATICTEXT6, _("0/4"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT6"));
    BoxSizer2->Add(Total_progress_percent, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer11->Add(BoxSizer2, 1, wxTOP|wxBOTTOM|wxRIGHT|wxALIGN_LEFT|wxALIGN_BOTTOM, 5);
    FlexGridSizer7->Add(FlexGridSizer11, 1, wxBOTTOM|wxRIGHT|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer1->Add(FlexGridSizer7, 1, wxBOTTOM|wxRIGHT|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Panel1->SetSizer(FlexGridSizer1);
    FlexGridSizer1->Fit(Panel1);
    FlexGridSizer1->SetSizeHints(Panel1);
    FlexGridSizer10 = new wxFlexGridSizer(0, 2, 0, 0);
    FlexGridSizer13 = new wxFlexGridSizer(0, 1, 0, 0);
    //StaticBoxSizer3 = new wxStaticBoxSizer(wxHORIZONTAL, Panel2, _T("选择"));
    StaticBoxSizer3 = new wxStaticBoxSizer(sbox3, wxHORIZONTAL);
    FlexGridSizer14 = new wxFlexGridSizer(0, 1, 0, 0);
    RadioButton_latest = new wxRadioButton(Panel2, ID_RADIOBUTTON1, _T("最近退粉"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_RADIOBUTTON1"));
    RadioButton_latest->Disable();
    FlexGridSizer14->Add(RadioButton_latest, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    RadioButton_recycler = new wxRadioButton(Panel2, ID_RADIOBUTTON2, _T("粉丝回收站"), wxDefaultPosition, wxSize(86,16), 0, wxDefaultValidator, _T("ID_RADIOBUTTON2"));
    RadioButton_recycler->SetValue(true);
    FlexGridSizer14->Add(RadioButton_recycler, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Button_review_select = new wxButton(Panel2, ID_BUTTON9, _T("确定"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_BUTTON9"));
    FlexGridSizer14->Add(Button_review_select, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    StaticBoxSizer3->Add(FlexGridSizer14, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer13->Add(StaticBoxSizer3, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer13->Add(20,156,1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    FlexGridSizer10->Add(FlexGridSizer13, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Notebook2 = new wxNotebook(Panel2, ID_NOTEBOOK2, wxDefaultPosition, wxSize(362,294), 0, _T("ID_NOTEBOOK2"));
    /************************Now init some previous UI****************************************/

    YaHeiFont9 = wxFont(9,wxSWISS,wxFONTSTYLE_NORMAL,wxNORMAL,false,wxT("微软雅黑"),wxFONTENCODING_DEFAULT);
    YaHeiFont10= wxFont(10,wxSWISS,wxFONTSTYLE_NORMAL,wxNORMAL,false,wxT("微软雅黑"),wxFONTENCODING_DEFAULT);
    Gauge_sub->SetRange(100);
    Gauge_total->SetRange(100);

    Button_start_sync->Enable(false);
    Button_login_reset->Enable(false);
    RadioButton_recycler->SetValue(false);
    RadioButton_recycler->Enable(false);

    Button_login_OK->Enable(false);
    TextCtrl_verifier->Enable(false);
    Button_getVerifier->Enable(true);

    mUserID.Clear();
    mIsDisplayRecycler = false;
    mIsLogin = false;

#ifdef GUI_DEPENDENT
    CF = new CFollowersQueryInc(this);
#else
    CF = new CFollowersQueryInc();
#endif
    pCF_CS = new wxCriticalSection();
    wxCriticalSectionLocker CFlocker(*pCF_CS);

    mpLogin = new CLogin();
    mpLogin_CS = new wxCriticalSection();

    if(mpLogin->isLogin())
    {
        mIsDisplayRecycler = true;
        mIsLogin = true;
        mUserID = CF->getSystemParam("user_id");
        TextCtrl_verifier->SetValue(CF->getSystemParam("last_used_PIN"));

        Button_login_reset->Enable(true);
        Button_start_sync->Enable(true);
        Button_getVerifier->Enable(false);

        unfollowed_from_recycler.clear();
        unfollowed_from_recycler = CF->query("select * from T_followers_recycler");
        build_unfollowed_UI(unfollowed_from_recycler);

        if(CF->countTable("T_followers_recycler")>0)
        {
            Button_clear_recycler->Enable(true);
            RadioButton_recycler->Enable(true);
            RadioButton_recycler->SetValue(true);
        }
        else
        {
            Button_clear_recycler->Enable(false);
        }

        if(CF->countTable("T_followers_record")>0)
        {
            Button_clear_record->Enable(true);
        }
        else
        {
            Button_clear_record->Enable(false);
        }


        //delete mpLogin;
        //delete mpLogin_CS;
        //mpLogin = NULL;
        //mpLogin_CS = NULL;
    }

    Connect(ID_BUTTON9,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_review_selectClick);
    Connect(ID_BUTTON2,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_login_resetClick);

    /**********************************************************************/
    FlexGridSizer10->Add(Notebook2, 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
    Panel2->SetSizer(FlexGridSizer10);
    FlexGridSizer10->Fit(Panel2);
    FlexGridSizer10->SetSizeHints(Panel2);
    Notebook1->AddPage(Panel1, _T("登录和开始"), false);
    Notebook1->AddPage(Panel2, _T("粉丝回收站"), false);
    MenuBar1 = new wxMenuBar();
    Menu1 = new wxMenu();
    MenuItem1 = new wxMenuItem(Menu1, idMenuQuit, _T("退出\tAlt-F4"), _T("退出程序"), wxITEM_NORMAL);
    Menu1->Append(MenuItem1);
    MenuBar1->Append(Menu1, _T("文件"));
    Menu2 = new wxMenu();
    MenuItem2 = new wxMenuItem(Menu2, idMenuAbout, _T("关于\tF1"), _T("查看版本信息"), wxITEM_NORMAL);
    Menu2->Append(MenuItem2);
    /*******************Custom About Info*******************/
    wxMenuItem* MenuItem3 = new wxMenuItem(Menu2, ID_AT_ME, _T("@死胖子GuiQing"), _T("去微博看看"), wxITEM_NORMAL);
    Menu2->Append(MenuItem3);
    /********************************************************/
    MenuBar1->Append(Menu2, _T("帮助"));
#ifdef UNIT_TEST
    wxMenu* Menu_UnitTest = new wxMenu();

    const long URL_ENCODE = wxNewId();
    const long OUATH_TIME_STAMP = wxNewId();
    const long OAUTH_NONCE = wxNewId();
    const long OAUTH_SORT = wxNewId();
    const long OAUTH_BASESTRING = wxNewId();
    const long OAUTH_SHA1 = wxNewId();
    const long OAUTH_REQ_HEADER = wxNewId();
    const long OAUTH_REQ_TEST = wxNewId();
    const long OAUTH_ACCESS_TEST = wxNewId();
    const long HTTP_PARAMS_EXTRACTION_TEST = wxNewId();
    const long XML_SAMPLER = wxNewId();
    const long XML_VALIDATOR = wxNewId();
    const long XML_REF_FIND = wxNewId();
    const long XML_ERROR_CORRECTION = wxNewId();

    wxMenuItem* MenuItem_Utf8UrlEncode = new wxMenuItem(Menu_UnitTest, URL_ENCODE, _T("UTF8 URLencode"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Oauth_timestamp = new wxMenuItem(Menu_UnitTest, OUATH_TIME_STAMP, _T("Timestamp"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Oauth_nonce = new wxMenuItem(Menu_UnitTest, OAUTH_NONCE, _T("Nonce"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Oauth_sort = new wxMenuItem(Menu_UnitTest, OAUTH_SORT, _T("Sort"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Oauth_baseString = new wxMenuItem(Menu_UnitTest, OAUTH_BASESTRING, _T("BaseString"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Oauth_SHA1 = new wxMenuItem(Menu_UnitTest, OAUTH_SHA1, _T("SHA1"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Oauth_ReqTokenHeader = new wxMenuItem(Menu_UnitTest, OAUTH_REQ_HEADER, _T("ReqTokenHeader"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Oauth_ReqTokenTest = new wxMenuItem(Menu_UnitTest, OAUTH_REQ_TEST, _T("ReqTokenTest"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Oauth_AccessTokenTest = new wxMenuItem(Menu_UnitTest, OAUTH_ACCESS_TEST, _T("AccessTokenTest"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_Http_ParamsExtractionTest = new wxMenuItem(Menu_UnitTest, HTTP_PARAMS_EXTRACTION_TEST, _T("HttpParamsExtraction"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_XML_samplerTest = new wxMenuItem(Menu_UnitTest, XML_SAMPLER, _T("XML sampler"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_XML_validatorTest = new wxMenuItem(Menu_UnitTest, XML_VALIDATOR, _T("XML validator"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_XML_refFindTest = new wxMenuItem(Menu_UnitTest, XML_REF_FIND, _T("XML refFind"), _T(""), wxITEM_NORMAL);
    wxMenuItem* MenuItem_XML_errorCorrectionTest = new wxMenuItem(Menu_UnitTest, XML_ERROR_CORRECTION, _T("XML errorCorrection"), _T(""), wxITEM_NORMAL);

    Connect(URL_ENCODE, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_URLencode);
    Connect(OUATH_TIME_STAMP, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_Oauth_Timestamp);
    Connect(OAUTH_NONCE, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_Oauth_Nonce);
    Connect(OAUTH_SORT, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_Oauth_Sort);
    Connect(OAUTH_BASESTRING, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_Oauth_BaseString);
    Connect(OAUTH_SHA1, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_Oauth_Sha1);
    Connect(OAUTH_REQ_HEADER, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_Oauth_ReqTokenHeader);
    Connect(OAUTH_REQ_TEST, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_Oauth_ReqTokenTest);
    Connect(OAUTH_ACCESS_TEST, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_Oauth_AccessTokenTest);
    Connect(HTTP_PARAMS_EXTRACTION_TEST, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_HttpParamsExtraction);
    Connect(XML_SAMPLER, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_XML_sampler);
    Connect(XML_VALIDATOR, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_XML_validator);
    Connect(XML_REF_FIND, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_XML_refFind);
    Connect(XML_ERROR_CORRECTION, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::Test_XML_errorCorrection);

    Menu_UnitTest->Append(MenuItem_Utf8UrlEncode);
    Menu_UnitTest->Append(MenuItem_Oauth_timestamp);
    Menu_UnitTest->Append(MenuItem_Oauth_nonce);
    Menu_UnitTest->Append(MenuItem_Oauth_sort);
    Menu_UnitTest->Append(MenuItem_Oauth_baseString);
    Menu_UnitTest->Append(MenuItem_Oauth_SHA1);
    Menu_UnitTest->Append(MenuItem_Oauth_ReqTokenHeader);
    Menu_UnitTest->Append(MenuItem_Oauth_ReqTokenTest);
    Menu_UnitTest->Append(MenuItem_Oauth_AccessTokenTest);
    Menu_UnitTest->Append(MenuItem_Http_ParamsExtractionTest);
    Menu_UnitTest->Append(MenuItem_XML_samplerTest);
    Menu_UnitTest->Append(MenuItem_XML_validatorTest);
    Menu_UnitTest->Append(MenuItem_XML_refFindTest);
    Menu_UnitTest->Append(MenuItem_XML_errorCorrectionTest);

    MenuBar1->Append(Menu_UnitTest, _T("Unit Test"));
#endif

    SetMenuBar(MenuBar1);
    StatusBar1 = new wxStatusBar(this, ID_STATUSBAR1, 0, _T("ID_STATUSBAR1"));
    int __wxStatusBarWidths_1[1] = { -1 };
    int __wxStatusBarStyles_1[1] = { wxSB_NORMAL };
    StatusBar1->SetFieldsCount(1,__wxStatusBarWidths_1);
    StatusBar1->SetStatusStyles(1,__wxStatusBarStyles_1);
    SetStatusBar(StatusBar1);

    Connect(ID_BUTTON_GET_VERIFIER,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_get_verifier);
    Connect(ID_BUTTON1,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_submit_verifier);
    Connect(ID_BUTTON3,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_start_syncClick);
    Connect(ID_BUTTON5,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_clear_recordClick);
    Connect(ID_BUTTON7,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_clear_recyclerClick);
    Connect(idMenuQuit,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnQuit);
    Connect(idMenuAbout,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&wxTsina_GUIFrame::OnAbout);
    //*)

    /*******************Font Settings*******************************/

    //StaticBoxSizer1->SetFont(YaHeiFont10);
    //StaticBoxSizer2->SetFont(YaHeiFont10);
    Connect(ID_AT_ME, wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&wxTsina_GUIFrame::OnAtMe);

    Total_progress_percent->SetFont(YaHeiFont10);
    Sub_progress_percent->SetFont(YaHeiFont10);
    Total_progress_text->SetFont(YaHeiFont10);
    Sub_progress_text->SetFont(YaHeiFont10);

    Notebook1->SetFont(YaHeiFont9);
    Notebook2->SetFont(YaHeiFont9);

    StaticText1->SetFont(YaHeiFont10);
    //StaticText2->SetFont(YaHeiFont10);
    sbox1->SetFont(YaHeiFont10);
    sbox2->SetFont(YaHeiFont10);
    sbox3->SetFont(YaHeiFont10);

    TextCtrl_verifier->SetFont(YaHeiFont9);
    //TextCtrl_password->SetFont(YaHeiFont9);

    Button_login_OK->SetFont(YaHeiFont9);
    Button_login_reset->SetFont(YaHeiFont9);
    Button_start_sync->SetFont(YaHeiFont9);
    Button_clear_record->SetFont(YaHeiFont9);
    Button_clear_recycler->SetFont(YaHeiFont9);
    RadioButton_latest->SetFont(YaHeiFont10);
    RadioButton_recycler->SetFont(YaHeiFont10);
    Button_review_select->SetFont(YaHeiFont9);
    MenuBar1->SetFont(YaHeiFont10);
    /************************Tool Tips*****************************/
    Button_start_sync->SetToolTip(_T("把之前保存的粉丝与现在的粉丝比对"));
    Button_clear_record->SetToolTip(_T("清空之前保存的粉丝，下次重新接收完整数据"));
    Button_login_reset->SetToolTip(_T("不记录密码，下次重新登录"));
    RadioButton_latest->SetToolTip(_T("这次同步中发现退粉的"));
    RadioButton_recycler->SetToolTip(_T("以前所有退粉的"));
    /*******************   MT    Events    Binding********************/
    //Update gauge
    Connect(wxID_ANY, EVT_UPDATE_SUB_GAUGE ,(wxObjectEventFunction)&wxTsina_GUIFrame::OnUpdateSubGauge);
    Connect(wxID_ANY, EVT_PULSE_SUB_GAUGE ,(wxObjectEventFunction)&wxTsina_GUIFrame::OnSubGaugePulse);
    Connect(wxID_ANY, EVT_UPDATE_TOTAL_GAUGE ,(wxObjectEventFunction)&wxTsina_GUIFrame::OnUpdateTotalGauge);
    Connect(wxID_ANY, EVT_PULSE_TOTAL_GAUGE ,(wxObjectEventFunction)&wxTsina_GUIFrame::OnTotalGaugePulse);
    Connect(wxID_ANY, EVT_GET_PIN_DONE ,(wxObjectEventFunction)&wxTsina_GUIFrame::OnGetPinDone);
    Connect(wxID_ANY, EVT_LOGIN_DONE ,(wxObjectEventFunction)&wxTsina_GUIFrame::OnLoginDone);
    Connect(wxID_ANY, EVT_CF_SYNC_DONE ,(wxObjectEventFunction)&wxTsina_GUIFrame::OnCFsyncDone);
}


wxTsina_GUIFrame::~wxTsina_GUIFrame()
{
    //(*Destroy(wxTsina_GUIFrame)
    //*)
}

void wxTsina_GUIFrame::OnQuit(wxCommandEvent& event)
{
    if(NULL != mpLogin)
    {
        delete mpLogin;
        mpLogin = NULL;
    }

    if(NULL != mpLogin_CS)
    {
        delete mpLogin_CS;
        mpLogin_CS = NULL;
    }

    delete CF;
    delete pCF_CS;

    delete sbox1;
    delete sbox2;
    delete sbox3;

    delete Total_progress_percent;
    delete Total_progress_text;
    delete Sub_progress_text;
    delete Gauge_sub;
    delete Sub_progress_percent;
    delete Gauge_total;

    CF=NULL;
    pCF_CS = NULL;

    sbox1=NULL;
    sbox2=NULL;
    sbox3=NULL;

    Total_progress_percent=NULL;
    Total_progress_text=NULL;
    Sub_progress_text=NULL;
    Gauge_sub=NULL;
    Sub_progress_percent=NULL;
    Gauge_total=NULL;

    THREADMAN.cleanAllThreads();
    Close();
}

void wxTsina_GUIFrame::OnAbout(wxCommandEvent& event)
{
    //wxString msg = wxbuildinfo(long_f);
    //wxMessageBox(msg, _("Welcome to..."));
    wxString aboutStr(wxString(_T("粉丝回收站 v"))<<VERSION<<wxString("\n"));
    aboutStr<<(_T("http://t.sina.com.cn/guiqing0402"));
    wxMessageBox(aboutStr);
}

void wxTsina_GUIFrame::OnAtMe(wxCommandEvent& event)
{
    wxLaunchDefaultBrowser(wxString("http://t.sina.com.cn/guiqing0402"));
}

//find the page index of Notebook2 from IDs of wxControl
int wxTsina_GUIFrame::matchIDs(long ID , std::vector<long> IDvec)
{
    int i = 0;
    for(std::vector<long>::iterator itr = IDvec.begin(); itr != IDvec.end(); ++itr , ++i)
    {
        if(*itr==ID)
        {
            return i;
        }
    }

    return -1;
}

void wxTsina_GUIFrame::build_unfollowed_UI(tableType& unfollowed_info)
{
    //Note : the offical code sample didn't provide such things as "delete wx..."
    //So, I temporarily assume that's OK, absolutly...
    v_panel.clear();
    v_flexGS_2col.clear();
    v_flexGS_left.clear();
    v_flexGS_right.clear();
    v_bmpButton_avatar.clear();
    v_bmpButton_avatar_ID.clear();
    v_bmpButton_hasAvatar.clear();
    v_button_unfo_ID.clear();
    v_button_remv_ID.clear();
    v_isFollow.clear();
    v_button_unfo.clear();
    v_button_remv.clear();
    v_unfollowed_info.clear();

    // Note that they just share the same index.
    // push_back() will make vec iterator invaild.
    // At this time, the conventional way works.
    std::vector< std::map<wxString, wxString> >::iterator itr;
    int i=0;

    wxMemoryBuffer* avatarMB = 0;
    wxMemoryInputStream* inputStream = 0;
    wxBitmap avatarBmp;

    Notebook2->Show(false);
    Notebook2->DeleteAllPages();
    imgList.RemoveAll();
    Notebook2->SetImageList(&imgList);

    for(itr = unfollowed_info.begin();itr!=unfollowed_info.end();++itr)
    {
        wxString profile("");
        profile<<wxString(_T("昵称："))<<wxString((*itr)["screen_name"]);
        if((*itr)["verified"]=="true")
        {
            profile<<wxString(_T("[V认证]"));
        }
        profile<<wxString("\n");

        if((*itr)["gender"]=="f")
        {
            profile<<wxString(_T("性别："))<<wxString(_T("女"))<<wxString("\n");
        }
        if((*itr)["gender"]=="m")
        {
            profile<<wxString(_T("性别："))<<wxString(_T("男"))<<wxString("\n");
        }

        profile<<wxString(_T("地区："))<<wxString((*itr)["location"])<<wxString("\n")
                <<wxString(_T("收藏："))<<wxString((*itr)["favourites_count"])<<wxString("\n")
                <<wxString(_T("关注："))<<wxString((*itr)["friends_count"])<<wxString("\n")
                <<wxString(_T("粉丝："))<<wxString((*itr)["followers_count"])<<wxString("\n");
        if((*itr)["description"] != "")
        {
            profile<<wxString(_T("个人说明："))<<wxString("\n    ")<<wxString((*itr)["description"])<<wxString("\n");
        }

        wxString recv_date((*itr)["created_at"]);
        profile<<wxString(_T("创建日期："))
                <<wxString(recv_date.substr(recv_date.find_first_of(" ")+1), recv_date.find(" ", recv_date.find(" ", recv_date.find_first_of(" ")+1)))
                <<wxString(_T(" , "))<<wxString(recv_date.substr(recv_date.find_last_of(" ")+1))<<wxString("\n");

        if((*itr)["domain"]!="")
        {
            profile<<wxString(_T("微博："))<<wxString(_T("http://t.sina.com.cn/"))<<wxString((*itr)["domain"])<<wxString("\n");
        }
        else
        {
            profile<<wxString(_T("微博："))<<wxString(_T("http://t.sina.com.cn/"))<<wxString((*itr)["id"])<<wxString("\n");
        }

        if((*itr)["url"]!="http://1" && (*itr)["url"] != "")
        {
            profile<<wxString(_T("博客："))<<wxString((*itr)["url"])<<wxString("\n");
        }

        v_panel.push_back(new wxPanel(Notebook2, wxNewId(), wxDefaultPosition, wxSize(344,250), wxTAB_TRAVERSAL));
        v_flexGS_2col.push_back(new wxFlexGridSizer(0, 2, 0, 0));
        v_flexGS_left.push_back(new wxFlexGridSizer(0, 1, 0, 0));
        v_bmpButton_avatar_ID.push_back(wxNewId());

        /***********************avatar onto buttons***************************/
        if(CF!=0)   // Just in case. CF should have been initialized before
        {
            wxCriticalSectionLocker CFlocker(*pCF_CS);
            #ifdef MT_DEBUG_LOG
            LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain build_unfollowed_UI");
            #endif
            avatarMB = CF->queryBLOB(wxString("SELECT profile_image FROM T_followers_recycler WHERE id='")<<(*itr)["id"]<<"'");
        }

        if(avatarMB !=0 && avatarMB->GetDataLen() != 0) //logic short circut will ensure -> won't ref a null ptr
        {
            delete inputStream;// Either 0 or =new , "delete" is always safe
            inputStream = new wxMemoryInputStream(avatarMB->GetData(), avatarMB->GetDataLen());
            //can not just wxImage(wxMemoryInputStream(...))
            //'Cause the param must be by ref, while the above was actually by value.
            avatarBmp = wxBitmap(wxImage(*inputStream));
            v_bmpButton_hasAvatar.push_back(true);
        }
        else
        {
            avatarBmp = wxBitmap(wxArtProvider::GetBitmap(wxART_MAKE_ART_ID_FROM_STR(_T("wxART_QUESTION")),wxART_CMN_DIALOG));
            v_bmpButton_hasAvatar.push_back(false);
        }
        v_bmpButton_avatar.push_back(new wxBitmapButton(
                    v_panel[i],v_bmpButton_avatar_ID[i],avatarBmp,
                    wxDefaultPosition,wxSize(60,62)));
        /******************************************************************/
        v_bmpButton_avatar[i]->SetDefault();
        v_bmpButton_avatar[i]->SetToolTip(_T("去Ta的微博看看"));
        Connect(v_bmpButton_avatar_ID[i] , wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_avatarClick);
        v_flexGS_left[i]->Add(v_bmpButton_avatar[i], 1, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
        //Accouding to the online doc , wxNewId() can give a conflict ID while wxID_ANY not .
        //But actually wxID_ANY gives you a -1 for everything !!! So how can I use it for identifying my buttons ?
        v_button_unfo_ID.push_back(wxNewId());
        v_button_unfo.push_back(new wxButton(v_panel[i], v_button_unfo_ID[i], _T("取消关注"), wxDefaultPosition, wxSize(68,24), 0, wxDefaultValidator));
        v_button_unfo[i]->SetFont(YaHeiFont9);
        if((*itr)["following"]=="false")
        {
            v_isFollow.push_back(new wxStaticText(v_panel[i], wxNewId(), _T("未关注"), wxDefaultPosition, wxDefaultSize, 0));
            v_isFollow[i]->SetFont(YaHeiFont10);
            v_button_unfo[i]->Disable();
            imgList.Add(wxArtProvider::GetIcon(wxART_INFORMATION));
        }
        else
        {
            v_isFollow.push_back(new wxStaticText(v_panel[i], wxNewId(), _T("已关注"), wxDefaultPosition, wxDefaultSize, 0));
            v_isFollow[i]->SetFont(YaHeiFont10);
            imgList.Add(wxArtProvider::GetIcon(wxART_WARNING));
            v_button_unfo[i]->Enable(true);
            /*********Evt Binding*************/
            //Why bind() is not defined , while the official doc keeps so strongly recommanding it and deprecate Connect()
            //Bind( wxEVT_COMMAND_BUTTON_CLICKED, &wxTsina_GUIFrame::OnButton_unfoClick, this, wxID_EXIT);
            Connect(v_button_unfo_ID[i] , wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_unfoClick);
        }
        v_flexGS_left[i]->Add(v_isFollow[i], 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
        v_flexGS_left[i]->Add(v_button_unfo[i], 1, wxALL|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
        v_button_remv_ID.push_back(wxNewId());

        v_button_remv.push_back(new wxButton(v_panel[i], v_button_remv_ID[i], _T("删除Ta"), wxDefaultPosition, wxSize(68,24), 0, wxDefaultValidator));
        v_button_remv[i]->SetFont(YaHeiFont9);
        v_button_remv[i]->SetToolTip(_T("从粉丝回收站中删除(不可恢复)"));
        /*********Evt Binding*************/
        Connect(v_button_remv_ID[i] , wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction)&wxTsina_GUIFrame::OnButton_remvClick);

        v_flexGS_left[i]->Add(v_button_remv[i], 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
        v_flexGS_left[i]->Add(20,78,1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
        v_flexGS_2col[i]->Add(v_flexGS_left[i], 1, wxALL|wxALIGN_LEFT|wxALIGN_TOP, 5);
        v_flexGS_right.push_back(new wxFlexGridSizer(0, 1, 0, 0));
        v_unfollowed_info.push_back(
                                new wxTextCtrl(v_panel[i], wxNewId(), profile, wxDefaultPosition, wxSize(256,256),
                                wxTE_AUTO_SCROLL|wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH|wxTE_AUTO_URL, wxDefaultValidator));
        v_unfollowed_info[i]->SetFont(YaHeiFont10);
        v_flexGS_right[i]->Add(v_unfollowed_info[i], 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
        v_flexGS_2col[i]->Add(v_flexGS_right[i], 1, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 5);
        v_panel[i]->SetSizer(v_flexGS_2col[i]);
        v_flexGS_2col[i]->SetSizeHints(v_panel[i]);

        //Current page build complete
        Notebook2->AddPage(v_panel[i], (*itr)["screen_name"], false,i);
        ++i;

    }//End of for(infoTable)

    /********Free mem resouces*******/
    // inputStream can't be delete here , it will crash the app.
    //I don't know why. So , I delete it only when re-init.
    inputStream = 0;
    avatarMB = 0;//No worry , avatarMB is refenercing a self-managed ptr in CQuery. Just leave, no delete.

    Notebook2->Show(true);
}

void wxTsina_GUIFrame::OnButton_get_verifier(wxCommandEvent& event)
{
    //pCF_CS for excluded operating systemDB of CF
    //Clogin has its primitive CS , don't worry
    if(NULL != mpLogin && NULL != pCF_CS)
    {
        pGetPinMT = new BackendWorker_GetPIN(this , pCF_CS);
        pGetPinMT->startWorking(mpLogin);
        Button_getVerifier->Enable(false);
    }
}

void wxTsina_GUIFrame::OnGetPinDone(wxThreadEvent& event)
{
    //TO DO : try to delete this event when used
    uint8_t resultFlag = event.GetPayload<uint8_t>();   // simple result , no need bitwise
    if(CLogin::REQUEST_TOKEN_UNAUTHORIZED == resultFlag)
    {
        //sometimes your request is denied for wrong signature with the same algorithm....wtf
        //then your sequential request will be denied with no condition....wtf
        wxMessageBox(wxString(wxT("-_-!  授权被拒绝 ... 请重开软件，再获取授权码")));
    }
    else if(CLogin::NO_ERROR == resultFlag)
    {
        if(NULL != CF && !(CF->getSystemParam("request_token").IsEmpty()))
        {
            TextCtrl_verifier->Enable(true);
            Button_login_OK->Enable(true);
            wxMessageBox(wxString(wxT("^_^  请记录下授权码")));
            wxLaunchDefaultBrowser(wxString(VERIFY_REQUEST_TOKEN_API)<<CF->getSystemParam("request_token"));
        }
        else
        {
            // should not happen
            wxMessageBox(wxString(wxT("Orz  获取失败 ... 请向开发者反馈此问题")));
        }

    }
    else if(CLogin::HTTP_DISCONNECTED == resultFlag)
    {
        wxMessageBox(wxT("(⊙_⊙?) ...   无法连接，请确认网络畅通"));
    }
    else if(CLogin::REQUEST_TOKEN_UNRECOGNIZED_DATA == resultFlag)
    {
        wxMessageBox(wxT("o(︶︿︶)o ...  网络传输错误，请重新获取授权码"));
    }
    else
    {
        //other http error
        wxMessageBox(wxString(wxT("(⊙_⊙?) 未知错误 ...  请重新获取授权码")));
    }

    Button_getVerifier->Enable(true);
}

void wxTsina_GUIFrame::OnButton_submit_verifier(wxCommandEvent& event)
{
    if(NULL != CF)
    {
        wxString previousPIN = CF->getSystemParam("last_used_PIN");
        if(! TextCtrl_verifier->GetLineText(0).IsEmpty())
        {
            if(previousPIN!=TextCtrl_verifier->GetLineText(0))
            {
                CF->setSystemParam("last_used_PIN", TextCtrl_verifier->GetLineText(0));

                pLoginMT = new BackendWorker_Login(this, pCF_CS);
                pLoginMT->startWorking(mpLogin, TextCtrl_verifier->GetLineText(0));

                TextCtrl_verifier->Enable(false);
                Button_login_OK->Enable(false);
            }
            else
            {
                wxMessageBox(wxT("╮(╯_╰)╭  这个授权码您已经用过了，请重新申请"));
            }
        }
        else
        {
            wxMessageBox(wxT("-_-|||  授权码不能为空"));
        }

    }
}

void wxTsina_GUIFrame::OnLoginDone(wxThreadEvent& event)
{
    //TO DO : more exception test
    uint8_t resultFlag = event.GetPayload<uint8_t>();
    if(CLogin::NO_ERROR == resultFlag)
    {
        TextCtrl_verifier->Enable(false);
        Button_login_OK->Enable(false);
        Button_getVerifier->Enable(false);
        Button_login_reset->Enable(true);
        Button_start_sync->Enable(true);
        wxMessageBox(wxString(wxT("^_^  登录成功")));
        return;
    }
    else if(CLogin::ACCESS_TOKEN_UNAUTHORIZED == resultFlag || CLogin::ACCOUNT_UNAUTHORIZED==resultFlag)
    {
        wxMessageBox(wxString(wxT("-_-!  授权被拒绝 ... 请重新获取授权码并填入")));
    }
    else if(CLogin::ACCESS_TOKEN_UNRECOGNIZED_DATA == resultFlag   || CLogin::ACCOUNT_UNRECOGNIZED_DATA == resultFlag)
    {
        wxMessageBox(wxString(wxT("o(︶︿︶)o  网络传输错误 ... 请重新获取授权码并填入")));
    }
    else if(CLogin::HTTP_DISCONNECTED == resultFlag)
    {
        wxMessageBox(_T("(⊙_⊙?) ...  无法连接，请确认网络畅通"));
    }
    else
    {
        //other http error
        wxMessageBox(wxString(wxT("(⊙_⊙?) 未知错误 ...  请重新获取授权码并填入")));
    }

    TextCtrl_verifier->Enable(true);
    Button_login_OK->Enable(true);
    Button_getVerifier->Enable(true);
    Button_login_reset->Enable(false);

    Refresh();
}

void wxTsina_GUIFrame::OnButton_start_syncClick(wxCommandEvent& event)
{
    if(mIsLogin)
    {
    #ifdef GUI_DEPENDENT
        CF = new CFollowersQueryInc(this);
    #else
        CF = new CFollowersQueryInc();
    #endif
        pCFsyncMT = new BackendWorker_CFsync(this, pCF_CS);
        if(pCFsyncMT->startWorking(CF, mUserID))
        {
            Button_start_sync->Enable(false);
            Button_login_reset->Enable(false);
        }
    }

}

void wxTsina_GUIFrame::OnCFsyncDone(wxThreadEvent& event)
{
    int8_t resultFlag = event.GetPayload<int8_t>(); //using bitwise for multiple feedback info

    Button_clear_record->Enable(true);
    Button_start_sync->Enable(true);
    Button_login_reset->Enable(true);

    wxCriticalSectionLocker CFlocker(*pCF_CS);
    #ifdef MT_DEBUG_LOG
    LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain CF sync done CB");
    #endif

    if((resultFlag>>pCFsyncMT->INIT_RECORD_DATA_OK) & 1)
    {
        CF->setSystemParam("recordCorrupted","false");
        try
        {
            if((resultFlag>>pCFsyncMT->FIND_UNFOLLOWED_OK) & 1)
            {
                Button_clear_recycler->Enable(true);

                if((resultFlag>>pCFsyncMT->UPDATE_NEW_FOLLOWED_OK) & 1)
                {
                    wxMessageBox( wxString(_T("新粉丝已保存，现在粉丝数："))<<CF->countTable("T_followers_record") );
                }

                if((resultFlag>>pCFsyncMT->HAS_ANY_ERROR) & 1) throw std::runtime_error("Over all process unfinished");

                #ifdef GUI_DEPENDENT
                SUB_GAUGE_UPDATE(wxString(_T("已完成")),100,this,__LINE__)
                TOTAL_GAUGE_UPDATE(wxString(_T("4/4")), 100, this,__LINE__);
                #endif

                wxMessageBox(wxString(_T("  ╭(╯^╰)╮  最近有"))<<CF->unfollowed.size()<<wxString(_T("人退粉...")));
                unfollowed_latest.clear();
                unfollowed_latest = CF->unfollowed;
                //Here unfollowed_from_recycler.size()==0 is used for a flag to tell remv_lick and avatar_click:
                //you should fetch info from unfollowed_latest rather than unfollowed_from_recycler
                //Clear unfollowed_from_recycler is safe.
                //'Cause when you review from the recycler , unfollowed_from_recycler will be re-filled, then everything is just OK.
                unfollowed_from_recycler.clear();
                build_unfollowed_UI(unfollowed_latest);
                RadioButton_latest->Enable(true);
                RadioButton_latest->SetValue(true);
                RadioButton_recycler->Enable(true);
                mIsDisplayRecycler = false;
                Notebook1->SetSelection(1);
            }
            else
            {
                //Unfinished errors only appears in false branch
                if((resultFlag>>pCFsyncMT->HAS_ANY_ERROR) & 1)
                {
                    throw std::runtime_error("Over all process unfinished");
                }
                if((resultFlag>>pCFsyncMT->UPDATE_NEW_FOLLOWED_OK) & 1)
                {
                    #ifdef GUI_DEPENDENT
                    SUB_GAUGE_UPDATE(wxString(_T("已完成")),100,this,__LINE__)
                    TOTAL_GAUGE_UPDATE(wxString(_T("4/4")), 100, this,__LINE__);
                    #endif
                    wxMessageBox( wxString(_T("最近没有人退粉，新粉丝已保存。现在粉丝数："))<<CF->countTable("T_followers_record") );
                }
                else
                {
                    if((resultFlag>>pCFsyncMT->HAS_ANY_ERROR) & 1) throw std::runtime_error("Over all process unfinished");
                    #ifdef GUI_DEPENDENT
                    SUB_GAUGE_UPDATE(wxString(_T("已完成")),100,this,__LINE__)
                    TOTAL_GAUGE_UPDATE(wxString(_T("4/4")), 100, this,__LINE__);
                    #endif
                    wxMessageBox(_T("最近没有人退粉，没有新粉丝"));
                }
            }// End of if(find_unfollowed)

        }catch(...)
        {
            wxMessageBox(wxString(_T("( ⊙o⊙ ) 哇，出错鸟...")));
        }
    }// End of if(initRecordData)
    else
    {
        wxMessageBox(_T("(⊙_⊙?) ...    无法连接，请确认网络畅通"));
    }// End of if(initRecordData) else

    Refresh();
}

void wxTsina_GUIFrame::OnButton_clear_recordClick(wxCommandEvent& event)
{
    wxCriticalSectionLocker CFlocker(*pCF_CS);
    #ifdef MT_DEBUG_LOG
        LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain clear record click");
    #endif

    //We don't need full info table here, 'cause it delete only by id
    // But you still need to encapsulate [id]s into vector to adapt to CFollowersQueryInc API
    if(CF->clearTable("T_followers_record"))
    {
        Button_clear_record->Enable(false);
        wxMessageBox(_T("粉丝记录已清空"));
        //OnButton_start_syncClick(event);
    }
    else
    {
        wxMessageBox(_T("清除失败"));
    }

    // VACUUM [tablename] ?
}

void wxTsina_GUIFrame::OnButton_clear_recyclerClick(wxCommandEvent& event)
{
    wxCriticalSectionLocker CFlocker(*pCF_CS);
    #ifdef MT_DEBUG_LOG
        LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain clear recycler click");
    #endif

    if(CF->clearTable("T_followers_recycler"))
    {
        Button_clear_recycler->Enable(false);
        if(RadioButton_recycler->GetValue())
        {
            Notebook2->DeleteAllPages();
        }
        RadioButton_recycler->SetValue(false);
        RadioButton_recycler->Enable(false);
        wxMessageBox(_T("粉丝回收站已清空"));
    }
    else
    {
        wxMessageBox(_T("清除失败"));
    }
}

void wxTsina_GUIFrame::OnButton_login_resetClick(wxCommandEvent& event)
{
    wxCriticalSectionLocker CFlocker(*pCF_CS);
    #ifdef MT_DEBUG_LOG
        LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain login reset click");
    #endif

    CF->deleteSystemParam("request_token");
    CF->deleteSystemParam("request_secret");
    CF->deleteSystemParam("access_token");
    CF->deleteSystemParam("access_secret");
    CF->deleteSystemParam("user_id");
    CF->deleteSystemParam("followers_count");
    CF->deleteSystemParam("friends_count");

    if(NULL != mpLogin)
    {
        mpLogin->logout();
    }
    TextCtrl_verifier->SetValue("");
    TextCtrl_verifier->Enable(false);
    Button_login_OK->Enable(false);
    Button_login_reset->Enable(false);
    Button_start_sync->Enable(false);
    Button_clear_record->Enable(false);
    Button_clear_recycler->Enable(false);
    Button_getVerifier->Enable(true);
    mIsLogin = false;
    mIsDisplayRecycler = false;
    Notebook2->DeleteAllPages();

    Refresh();
}

void wxTsina_GUIFrame::OnButton_review_selectClick(wxCommandEvent& event)
{
    if(RadioButton_latest->GetValue() && mIsLogin && mIsDisplayRecycler && unfollowed_latest.size() != 0)
    {
        //mIsDisplayRecycler : Avoid useless refresh
        //size() : Just in case , [ ] ref a null vector will crash app
        build_unfollowed_UI(unfollowed_latest);
        unfollowed_from_recycler.clear();
        mIsDisplayRecycler = false;
    }

    if(RadioButton_recycler->GetValue() && (! mIsDisplayRecycler) && mIsLogin)
    {
        unfollowed_from_recycler.clear();
        wxCriticalSectionLocker CFlocker(*pCF_CS);
        #ifdef MT_DEBUG_LOG
        LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain review select click");
        #endif
        unfollowed_from_recycler = CF->query("select * from T_followers_recycler");
        if(unfollowed_from_recycler.size() != 0)
        {
            build_unfollowed_UI(unfollowed_from_recycler);
            mIsDisplayRecycler = true;
        }
    }
    else if(! mIsLogin)
    {
        wxMessageBox(_T("需要登录"));
    }
}

void wxTsina_GUIFrame::OnButton_unfoClick(wxCommandEvent& event)
{
    wxString targetID("");
    wxString screenName("");
    int followerIndex = matchIDs(event.GetId(), v_button_unfo_ID);
    if((!mIsDisplayRecycler) && unfollowed_latest.size()!=0)
    {
        targetID = unfollowed_latest[followerIndex]["id"];
        screenName = unfollowed_latest[followerIndex]["screen_name"];
    }
    else if(mIsDisplayRecycler && unfollowed_from_recycler.size()!=0)
    {
        targetID = unfollowed_from_recycler[followerIndex]["id"];
        screenName = unfollowed_from_recycler[followerIndex]["screen_name"];
    }

    wxCriticalSectionLocker CFlocker(*pCF_CS);
    #ifdef MT_DEBUG_LOG
        LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain unfo click");
    #endif
    if(CF->unfollow(targetID))
    {
        v_isFollow[followerIndex]->SetLabel(_T("未关注"));
        v_button_unfo[followerIndex]->Disable();
        imgList.Replace(followerIndex, wxArtProvider::GetIcon(wxART_INFORMATION));
        Notebook2->SetPageImage(followerIndex, followerIndex);
        wxMessageBox(wxString(_T("已对\""))<<screenName<<_T("\"取消关注"));
    }
    else
    {
        wxMessageBox(_T("操作失败"));
    }
}

void wxTsina_GUIFrame::OnButton_remvClick(wxCommandEvent& event)
{
    if(mIsLogin)
    {
        int followerIndex = matchIDs(event.GetId(), v_button_remv_ID);
        tableType toBeDeleted;// To match the delete API , I have to encapsulate info into tableType

        //In this case , client delete followers just from latest
        //You got no chance to fetch & fill unfollowed_from_recycler
        if(!mIsDisplayRecycler)
        {
            //Now , followerIndex is specific for latest vec
            //You should use the index to fetch from unfollowed_latest only
            //Either , you can't replace unfollowed_latest with unfollowed_from_recycler
            toBeDeleted.push_back(unfollowed_latest[followerIndex]);
            //The above is just prepare to delete from recycler
            //Here , unfollowed_latest should be also synchronized deleted.
            //Otherwise , avatar click will get a wrong URL from unfollowed_latest.
            unfollowed_latest.erase(unfollowed_latest.begin()+followerIndex);
        }
        else
        {
            toBeDeleted.push_back(unfollowed_from_recycler[followerIndex]);
        }

        wxCriticalSectionLocker CFlocker(*pCF_CS);
        #ifdef MT_DEBUG_LOG
        LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain remove from recycler");
        #endif
        if(CF->deleteFollowers(toBeDeleted, "T_followers_recycler"))
        {
            Notebook2->DeletePage(followerIndex);

            //But Notebook UI currently use these vecs to work , while these vecs are just copies of the old  infoTable
            //So , get them up to date
            v_panel.erase(v_panel.begin()+followerIndex);
            v_flexGS_2col.erase(v_flexGS_2col.begin()+followerIndex);
            v_flexGS_left.erase(v_flexGS_left.begin()+followerIndex);
            v_flexGS_right.erase(v_flexGS_right.begin()+followerIndex);
            v_bmpButton_avatar.erase(v_bmpButton_avatar.begin()+followerIndex);
            v_bmpButton_avatar_ID.erase(v_bmpButton_avatar_ID.begin()+followerIndex);
            v_button_unfo_ID.erase(v_button_unfo_ID.begin()+followerIndex);
            v_button_remv_ID.erase(v_button_remv_ID.begin()+followerIndex);
            v_isFollow.erase(v_isFollow.begin()+followerIndex);
            v_button_unfo.erase(v_button_unfo.begin()+followerIndex);
            v_button_remv.erase(v_button_remv.begin()+followerIndex);
            v_unfollowed_info.erase(v_unfollowed_info.begin()+followerIndex);

            wxMessageBox( wxString(_T("已经从粉丝回收站中删除“"))
                                <<wxString(toBeDeleted[0]["screen_name"])
                                <<wxString(_T("”")) );

            //Ensure the info table is up to date
            unfollowed_from_recycler.clear();
            unfollowed_from_recycler = CF->query("select * from T_followers_recycler");

            //Maybe this is lower effciency than re-build UI(for erasing is slower than push_back)
            //Just for avoiding Notebook UI evidently refreshing during re-building.
        }//End of if(delete followers)
    }//End of if(mIsLogin)
}

void wxTsina_GUIFrame::OnButton_avatarClick(wxCommandEvent& event)
{
    //No need to login , t.sina will take this over
    int followerIndex = matchIDs(event.GetId(), v_bmpButton_avatar_ID);
    wxString targetUID("");
    wxString jpgURL("");

    wxCriticalSectionLocker CFlocker(*pCF_CS);
    #ifdef MT_DEBUG_LOG
        LOGMAN.logInfo("[MT] Enter CS in wxTsina_GUIMain avatar click");
    #endif
    //size() != 0 is not only checking the flag(latest / recycler) , but also avoid [ ] to ref a null
    if((!mIsDisplayRecycler) && unfollowed_latest.size()!=0)
    {
        targetUID = unfollowed_latest[followerIndex]["id"];
        //If first fetchAndStore avatar failed , click will retry to fetch
        if(!v_bmpButton_hasAvatar[followerIndex] && CF != 0)
        {
            jpgURL = unfollowed_latest[followerIndex]["profile_image_url"].Remove(0,7);  // remove ("http://") in url
            CF->fetchAndStoreBLOB(jpgURL, unfollowed_latest[followerIndex]["id"], "T_followers_recycler", "profile_image");
        }
    }
    else if(mIsDisplayRecycler && unfollowed_from_recycler.size()!=0)
    {
        targetUID = unfollowed_from_recycler[followerIndex]["id"];
        //If first fetchAndStore avatar failed , click will retry to fetch
        if(!v_bmpButton_hasAvatar[followerIndex] && CF != 0)
        {
            jpgURL = unfollowed_from_recycler[followerIndex]["profile_image_url"].Remove(0,7);  // remove ("http://") in url
            CF->fetchAndStoreBLOB(jpgURL, unfollowed_from_recycler[followerIndex]["id"], "T_followers_recycler", "profile_image");
        }
    }


    if(targetUID!="")   //I know "" is safe but , just avoid undefined behaviour
    {
        wxLaunchDefaultBrowser( wxString("http://t.sina.com.cn/")<<targetUID);
    }
}

void wxTsina_GUIFrame::OnUpdateSubGauge(wxThreadEvent& event)
{
    //Note: in the definition,
    //template<T> T wxThreadEvent::GetPayload()
    //there's no input args to identify which version of GetPayload will be instanced
    //So you must be explictiy specify return type as below:
    const int percent = event.GetPayload< std::pair<const wxString, const int> >().second;
    const wxString text = event.GetPayload< std::pair<const wxString, const int> >().first;

    if(percent != -1)
    {
        Gauge_sub->SetValue(percent);
        Sub_progress_percent->SetLabel(wxString("")<<percent<<wxString("%"));
    }
    if(text != "")
    {
        Sub_progress_text->SetLabel(text);
    }

    Gauge_total->Pulse();
}

void wxTsina_GUIFrame::OnSubGaugePulse(wxThreadEvent& event)
{
    Gauge_sub->Pulse();
}

void wxTsina_GUIFrame::OnUpdateTotalGauge(wxThreadEvent& event)
{
    const int percent = event.GetPayload< std::pair<const wxString, const int> >().second;
    const wxString text = event.GetPayload< std::pair<const wxString, const int> >().first;

    if(percent >= 0)
    {
        Gauge_total->SetValue(percent);
    }

    if(text != "")
    {
        Total_progress_percent->SetLabel(text);
    }
}

void wxTsina_GUIFrame::OnTotalGaugePulse(wxThreadEvent& event)
{
    Gauge_total->Pulse();
}

#ifdef UNIT_TEST

///Unit test for ensure correct result in code optimization later

void wxTsina_GUIFrame::Test_URLencode(wxCommandEvent& event)
{

}
void wxTsina_GUIFrame::Test_Oauth_Timestamp(wxCommandEvent& event)
{
    wxMessageBox(UnitTest_OAuth::GetInstance().getTimestamp());
}

void wxTsina_GUIFrame::Test_Oauth_Nonce(wxCommandEvent& event)
{
    wxMessageBox(UnitTest_OAuth::GetInstance().getNonce());
}

void wxTsina_GUIFrame::Test_Oauth_Sort(wxCommandEvent& event)
{

}

void wxTsina_GUIFrame::Test_Oauth_BaseString(wxCommandEvent& event)
{
    wxString currentBaseString(UnitTest_OAuth::GetInstance().getBaseString());
    wxString correctBaseString("");

    correctBaseString<<wxString("POST&https%3A%2F%2Fapi.t.sina.com.cn%2Foauth%2Frequest_token&oauth_callback%3Dhttp%253A%252F%25");
    correctBaseString<<wxString("2Flocalhost%253A3005%252Fthe_dance%252Fprocess_callback%253Fservice_provider_id%253D11%26oauth_");
    correctBaseString<<wxString("consumer_key%3DGDdmIQH6jhtmLUypg82g%26oauth_nonce%3DQP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk");
    correctBaseString<<wxString("%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1272323042%26oauth_version%3D1.0");

    if(currentBaseString==correctBaseString)
    {
        /// only oauth_callback is processed by url_encode(url_encode(raw)) can reproduce this wierd given result. Wtf
        wxMessageBox("Test OK");
    }
    else
    {
        wxString result("Test Failed : \n\n");
        result<<currentBaseString;
        wxMessageBox(result);
    }
}

void wxTsina_GUIFrame::Test_Oauth_Sha1(wxCommandEvent& event)
{
    wxString finalResult("");

    // sign the base string

    wxString testCase1_result(UnitTest_OAuth::GetInstance().signRequest());
    if(testCase1_result==wxString("8wUi7m5HFQy76nowoCThusfgB+Q="))
    {
        ///Actually you never get this correct. Sina doc uses an unknown base string as SHA1 data. Wtf
        finalResult<<wxString("Test case 1 : SignRequest >>> OK");
    }
    else
    {
        finalResult<<wxString("Test case 1 : SignRequest >>> Failed :\n  ");
        finalResult<<testCase1_result;
    }


    //SHA1 crypt with a given data & key
    wxString testCase2_result(UnitTest_OAuth::GetInstance().HMAC_SHA1());
    if(testCase2_result==wxString("tR3+Ty81lMeYAr/Fid0kMTYa/WM="))
    {
        finalResult<<wxString("\n\nTest case 2 : HMAC_SHA1 >>> OK.");
    }
    else
    {
        finalResult<<wxString("\n\nTest case 2 : HMAC_SHA1 >>> Failed :\n  ");
        finalResult<<testCase2_result;
    }

    wxMessageBox(finalResult);
}

void wxTsina_GUIFrame::Test_Oauth_ReqTokenTest(wxCommandEvent& event)
{
    UnitTest_Login::GetInstance().getRequestToken();
}

void wxTsina_GUIFrame::Test_Oauth_ReqTokenHeader(wxCommandEvent& event)
{
    wxMessageBox(UnitTest_OAuth::GetInstance().getReqTokenHeader());
}

void wxTsina_GUIFrame::Test_Oauth_AccessTokenTest(wxCommandEvent& event)
{
    UnitTest_Login::GetInstance().getAccessToken(TextCtrl_verifier->GetLineText(0));
}

void wxTsina_GUIFrame::Test_HttpParamsExtraction(wxCommandEvent& event)
{
    UnitTest_OAuth::GetInstance().extractHttpParams();
}

void wxTsina_GUIFrame::Test_XML_sampler(wxCommandEvent& event)
{
    UnitTest_XMLValidator& testValidator = UnitTest_XMLValidator::GetInstance();
    if(testValidator.readXML("test_xml.xml"))
    {
        if(testValidator.parseXML())
        {
            wxMessageBox(testValidator.sampleXML_Test());
        }
    }
}

void wxTsina_GUIFrame::Test_XML_validator(wxCommandEvent& event)
{
    UnitTest_XMLValidator& testValidator = UnitTest_XMLValidator::GetInstance();
    if(testValidator.readXML("test_xml.xml"))
    {
        if(testValidator.parseXML())
        {
            wxMessageBox(testValidator.validateXML_Test());
        }
    }
}

void wxTsina_GUIFrame::Test_XML_refFind(wxCommandEvent& event)
{
    UnitTest_XMLValidator& testValidator = UnitTest_XMLValidator::GetInstance();
    if(testValidator.readXML("test_xml.xml"))
    {
        if(testValidator.parseXML())
        {
            wxMessageBox(testValidator.XMLRefFind_Test());
        }
    }
}

void wxTsina_GUIFrame::Test_XML_errorCorrection(wxCommandEvent& event)
{
    UnitTest_XMLValidator& testValidator = UnitTest_XMLValidator::GetInstance();
    if(testValidator.readXML("test_xml.xml"))
    {
        if(testValidator.parseXML())
        {
            wxMessageBox(testValidator.XMLErrorCorrection_Test());
        }
    }
}
#endif
